﻿Imports System
Imports System.Net
Imports System.Net.Sockets
Imports System.Collections.Concurrent
Imports System.Collections.Generic
Imports System.Threading
Imports System.Threading.Tasks
Imports Alchemy
Imports Alchemy.Classes
Imports Newtonsoft.Json

Public Class Server
    'GLOBAL VARIABLES

    'List of Connected WebSocket Clients <UserContext, Client Number>
    Dim clients As New ConcurrentDictionary(Of UserContext, Integer)()

    'Message Sending Task TEST CODE
    Dim sendMessages As New Task(New Action(AddressOf sendTest))

    'Stores an instance of the Server
    Dim wsServer

    'Time to quit?
    Dim quittingTime = False

    'Delegate to update UI
    Delegate Sub UpdateConsoleCallback(ByVal [s] As String)

    'Update Console Display - DO NOT CALL
    Sub updateConsole(ByVal [s] As String)
        Me.consoleBox.AppendText(DateTime.Now.TimeOfDay.ToString + " " + s + vbCrLf)
    End Sub

    'Decide Method and Update Console Display - Thread Safe
    Private Sub display(ByVal [s] As String)
        If Me.consoleBox.InvokeRequired Then
            Dim d As New UpdateConsoleCallback(AddressOf updateConsole)
            Me.Invoke(d, New Object() {[s]})
        Else
            updateConsole([s])
        End If
    End Sub

    'Start Server Button
    Private Sub btnStartServer_Click(sender As Object, e As EventArgs) Handles btnStartServer.Click
        btnEndServer.Enabled = True
        btnStartServer.Enabled = False
        start()

    End Sub

    'Stop Server Button
    Private Sub btnEndServer_Click(sender As Object, e As EventArgs) Handles btnEndServer.Click
        btnEndServer.Enabled = False
        btnStartServer.Enabled = True
        quit()
    End Sub

    'Server
    Private Sub start()
        'Environment Variables
        Dim port = 5001
        'WebSocket Server Port

        consoleBox.AppendText("Middle Tennessee State University" + vbCrLf)
        consoleBox.AppendText("RaiderRobotics 2013 - NASA Lunabotics Competition" + vbCrLf)
        consoleBox.AppendText(vbCrLf)
        consoleBox.AppendText("WebSocket Server:" + vbCrLf)
        consoleBox.AppendText("-----------------------------------------------------------" + vbCrLf)

        'Start WebSocket Server
        display("Starting WebSocket Server")

        'Creates server and binds events
        wsServer = New Alchemy.WebSocketServer(port, IPAddress.Any) With { _
            .OnReceive = AddressOf OnReceive, _
            .OnSend = AddressOf OnSend, _
            .OnConnected = AddressOf OnConnect, _
            .OnDisconnect = AddressOf OnDisconnect, _
            .TimeOut = New TimeSpan(0, 5, 0) _
        }

        wsServer.Start()

        display("Server started")

        sendMessages.Start()
    End Sub

    'Handles a Client Connecting
    Public Sub OnConnect(context As UserContext)
        display(context.ClientAddress.ToString + " just connected.")
        clients.TryAdd(context, clients.Count)
        'Add client to client dictionary
    End Sub

    'Handles a Client Disconnecting
    Public Sub OnDisconnect(context As UserContext)
        Dim returnVal As Integer
        display(context.ClientAddress.ToString + " just disconnected.")
        clients.TryRemove(context, returnVal)
        'Remove client from client dictionary
    End Sub

    'Handles Message Reciept
    Public Sub OnReceive(context As UserContext)
        display("Received message from " + context.ClientAddress.ToString)

        Try
            Dim json = context.DataFrame.ToString()
            Dim obj As [String] = JsonConvert.DeserializeObject(json).ToString()

            display(obj.ToString())
        Catch e As Exception
            ' Bad JSON! For shame.
            display("Bad JSON Message")
        End Try
    End Sub

    'Notification that a Message was Sent
    Public Sub OnSend(context As UserContext)
        display("Sent message to " + context.ClientAddress.ToString)
    End Sub

    '
    '         *  TEST CODE
    '         *  This sends a test JSON message every 5 seconds to the connected client. Just
    '         *  to prove that the connection is actually working.
    '         

    Private Sub sendTest()
        While Not quittingTime
            For Each i In clients
                i.Key.Send(JsonConvert.SerializeObject("Test"))
            Next

            'Wait 5 seconds between sending messages
            Thread.Sleep(5000)
        End While
    End Sub

    Public Sub quit()
        quittingTime = True
        wsServer.Stop()
    End Sub

End Class
